package wsi.dataguide.tree;

import java.util.List;

import org.rygh.core.model.common.StringSet;
import org.rygh.core.xml.AbstractXmlTree;
import org.rygh.core.xml.UXml;
import org.rygh.core.xml.XmlBuilder;
import org.rygh.core.xml.XmlObject;
import org.rygh.semantic.model.rdf.Prefix;

public class WSXmlTree extends AbstractXmlTree<WSXmlObject, WSXmlLeaf> {

	public WSXmlTree() {
		this(null);
	}

	public WSXmlTree(WSXmlObject rootObj) {
		super(new WSXmlLeaf(null, rootObj));

	}

	public void replaceValue(String old, String newStr) {
		if (old == null || old.trim().isEmpty())
			return;

		List<WSXmlLeaf> leaves = getAllLeaves();
		StringSet ss = new StringSet(old);

		for (WSXmlLeaf l : leaves) {
			String val = l.getValue().getValue();

			if (val == null || val.trim().isEmpty())
				continue;

			StringSet _ss = new StringSet(val);

			if (ss.equals(_ss))
				l.getValue().setValue(newStr);
		}
	}

	/**
	 * do not put xml header here any more. this is used by XmlTableNode
	 * 
	 * @return
	 */
	public String toWSXmlString() {
		StringBuilder sbuilder = new StringBuilder();

		if (root.isLeaf())
			toWSXmlString(sbuilder, root);
		else
			toWSXmlString(sbuilder, getConcreteRoot());

		return sbuilder.toString();
	}

	private void toWSXmlString(StringBuilder sbuilder, WSXmlLeaf leaf) {
		WSXmlObject node = leaf.getValue();

		boolean replaced = UXml.containsInvalidChar(node.getValue());
		boolean inverse = node.getValue().endsWith("(R)");

		String val = node.getValue();
		String val_ = inverse ? val.substring(0, val.length() - 3) : val;

		boolean prefix = Prefix.startsWithPrefix(val);

		sbuilder.append(String.format(
				"<%s%s%s>",
				replaced ? UXml.toValidXmlTag(val, prefix) : inverse ? val_
						: val,
				replaced ? String.format(" value=\"%s\"", XmlObject.escape(val))
						: "", inverse ? " direction=\"inverse\"" : ""));

		if (!leaf.isLeaf()) {
			for (WSXmlLeaf i : leaf.getChildren())
				toWSXmlString(sbuilder, i);
		}

		sbuilder.append(String.format("</%s>\r\n",
				replaced ? UXml.toValidXmlTag(val, prefix) : inverse ? val_
						: val));
	}

	/**
	 * we have to handle attributes as nodes carefully.
	 */
	@Override
	public String toXmlString() {
		XmlBuilder sbuilder = new XmlBuilder();

		toXmlString(0, sbuilder, getConcreteRoot());

		return sbuilder.getValue();
	}

	@Override
	protected void toXmlString(int level, XmlBuilder xbuilder, WSXmlLeaf node) {
		if (node == null)
			return;

		WSXmlObject obj = node.getValue();

		if (obj.isAttribute() || obj.getName().equals("_self"))
			return;

		String attr = obj.toAttributeString();
		String self = null;

		if (!node.isLeaf()) {
			for (WSXmlLeaf c : node.getChildren()) {
				WSXmlObject o = c.getValue();

				if (o.getName().equals("_self"))
					self = o.getValue();

				if (o.isAttribute())
					attr += String.format(" %s=\"%s\"", o.getName(),
							XmlObject.escape(o.getValue()));
			}
		}

		if (node.getParent().isRoot())
			xbuilder.begin(String.format("%s %s%s", obj.getName(),
					getPrefixString(), attr));
		else
			xbuilder.begin(String.format("%s%s", obj.getName(), attr));

		if (self != null)
			xbuilder.escape(self);

		if (node.isLeaf()) {
			String val = obj.getValue();

			if (val != null && !val.isEmpty())
				xbuilder.escape(obj.getValue());
		} else
			for (WSXmlLeaf i : node.getChildren())
				toXmlString(level + 1, xbuilder, i);

		xbuilder.end(obj.getName());
	}
}
